package com.baizhi.cmfz.aop;


import com.alibaba.fastjson.JSON;
import com.baizhi.cmfz.annotation.LogAnnotation;
import com.baizhi.cmfz.dao.LogDao;
import com.baizhi.cmfz.entiy.Admin;
import com.baizhi.cmfz.entiy.Banner;
import com.baizhi.cmfz.entiy.Log;
import com.baizhi.cmfz.util.IPKit;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.mybatis.logging.Logger;
import org.mybatis.logging.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.lang.reflect.TypeVariable;
import java.util.Date;



/*@Configuration  标记当前类有配置类
 @Aspect 标记当前类为切面类  会自动编织类中的增强和切点*/

@Configuration
@Aspect
public class LogAspect {

    private Logger logger = LoggerFactory.getLogger(LogAspect.class);
    //@Autowired
    //private LogDao dao;

    //1.定义切点，相当于以前的pointcut标签，可以通过切方法或切注解切入，
    // 切方法，统一处理简单，切注解  灵活
    //@Pointcut注解能够在一个@AspectJ切面内定义可重用的切点。
    @Pointcut("@annotation(com.baizhi.cmfz.annotation.LogAnnotation)")//此处用了自定义注解
    public void logPoint(){
        //通过在logPoint()方法上添加@Pointcut注解，这样就可以在任何的切点表达式中使用logPoint()了，
        //如果不这样做的话，你需要在这些地方使用那个更长的切点表达式。我们现在把所有通知注解中的长表达式都替换成了logPoint()。
        //logPoint()方法的实际内容并不重要，在这里它实际上应该是空的。其实该方法本身只是一个标识，供@Pointcut注解依附。
    }
    //2.定义增强
    @After("logPoint()")//定义的切点
    public void  logAfter(JoinPoint joinPoint){
        //   1.创建一个Log对象并获取需要的所有数据
        Log log = new Log();
        log.setLogDate(new Date());
        //   获取管理员的名字  session
        //       拿到当前线程对应的 request
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        HttpSession session = request.getSession();
        Admin admin = (Admin) session.getAttribute("login");
        //log.setUsername(admin.getUserName());
        //   获取ip地址
        String ipAddrByRequest = IPKit.getIpAddrByRequest(request);
        log.setLogIp(ipAddrByRequest);
        //   获取操作记录
        /**获取操作内容  执行不同的方法 需要获取到不同的操作内容
         * 如果执行 菜单的 SelectAll  获取到的应该是：查询全部菜单信息
         * 写死  传参  不行
         * 通过自定义注解
         * 1.在自定义注解里面可以写入操作内容
         * 2.可以获取到被执行方法的注解
         * 3.进而获取注解的内容  也就是操作内容
         */
        //        1. joinPoint 连接点对象 得到切点相关的信息
        // getSignature() 获取连接点的方法签名对象
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // getArgs（）获取连接点方法运行时的入参参数值
        Object[] args = joinPoint.getArgs();
        System.out.println("joinPoint.getArgs:" + JSON.toJSONString(args));
        //        2.因为注解加在了方法上，需获取当前正在执行的方法对象
        Method method = signature.getMethod();
        //        3.通过方法对象得到注解 参数：注解的类对象
        LogAnnotation annotation = method.getAnnotation(LogAnnotation.class);
        //  getParameterNames(method) 获取请求方法参数名称
        String[] parameterNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(method);
        System.out.println("parameterNames:" + JSON.toJSONString(parameterNames));
        String id = null;
        if (args != null && parameterNames != null){
            for (int i = 0; i < parameterNames.length ; i++) {
                if ("banner".equals(parameterNames[i])){
                    if (args[i] != null ){

                        Banner banner = (Banner) args[i];
                        System.out.println("banner.getBannerId:" + banner.getBannerId());
                        /*if (args[i] instanceof String){
                             id = (String)args[i];
                        }else if (args[i] instanceof Long){
                             id = args[i].toString();
                        }else*/
                    }else{
                        System.out.println("id: null");
                    }

                    System.out.println("id:" + id);

                }
            }
        }

        //        4.通过注解得到注解中的值  即操作的内容
        String value = annotation.value();
        System.out.println("annotation.value:" + value);

        //log.setLogContent(value);
//        2.将数据添加到数据库
        //dao.insert(log);
    }
}
